import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Representation extends Named implements QuiverChangedListener {
	public static String ZERO = "0";
	public static String ONE = "1";
    private Quiver quiver;
	private Map<Node, Integer> dimensions;
	private Map<Arrow, String[][]> maps;

	public Representation(Quiver quiver) {
		setQuiver(quiver);
		setName();
	}

	public void setQuiver(Quiver quiver) {
        this.quiver = quiver;
		dimensions = new HashMap<Node, Integer>();
		maps = new HashMap<Arrow, String[][]>();
		for (Node node : quiver.getNodes()) {
			dimensions.put(node, 0);
		}
		for (Arrow arrow : quiver.getArrows()) {
			maps.put(arrow, new String[0][0]);
		}
	}

	public static String[][] zeroMap(int width, int height) {
		String[][] map = new String[width][height];
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) {
				map[i][j] = ZERO;
			}
		}
		return map;
	}

	public static boolean isZeroMap(String[][] map) {
		if (map.length == 0 || map[0].length == 0) {
			return true;
		}
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				if (map[i][j] != ZERO) {
					return false;
				}
			}
		}
		return true;
	}

	public static String[][] identityMap(int width, int height) {
		String[][] map = zeroMap(width, height);
		for (int i = 0; i < Math.min(width, height); i++) {
			map[i][i] = ONE;
		}
		return map;
	}

	public void setDimension(Node node, int newDim) {
		int dim = dimensions.get(node);
		if (dim == newDim) {
			return;
		}
		dimensions.put(node, newDim);
		for (Arrow arrow : node.getArrows()) {
			String[][] map = maps.get(arrow);
			String[][] newMap = new String[getDimension(arrow.getFromNode())][getDimension(arrow
					.getToNode())];
			for (int i = 0; i < newMap.length; i++) {
				for (int j = 0; j < newMap[0].length; j++) {
					if (i < map.length && j < map[0].length) {
						newMap[i][j] = map[i][j];
					} else {
						newMap[i][j] = ZERO;
					}
				}
			}
			maps.put(arrow, newMap);
		}
	}

	public int getDimension(Node node) {
        return dimensions.get(node);
	}

    public void setMap(Arrow arrow, String[][] map) {
        dimensions.put(arrow.getFromNode(), map.length);
        dimensions.put(arrow.getToNode(), map[0].length);
        maps.put(arrow, map);
    }

	public String[][] getMap(Arrow arrow) {
		return maps.get(arrow);
	}

    @Override
    public String toString() {
        return "Representation{" +
                "dimensions=" + dimensions +
                ", maps=" + maps +
                '}';
    }

    @Override
	public String generateName(String preferredName) {
		if (preferredName == null || preferredName.isEmpty()) {
			preferredName = config.defaultRepresentationName;
		}
		if (preferredName.equals(name)) {
			return name;
		}
		Set<String> namePool = QuiverFrame.getInstance().getNamePool();
		String name = "";
		Set<Integer> used = new HashSet<Integer>();

		ArrayList<String> preferredNameParts = new ArrayList<String>(Arrays
				.asList(preferredName.split(",")));
		if (preferredName.endsWith(",")) {
			preferredNameParts.add("");
		}
		for (String preferredNamePart : preferredNameParts) {
			if (preferredNamePart.isEmpty()) {
				preferredNamePart = config.defaultArrowName;
			}
			int separation = digitSeparation(preferredNamePart);
			String tmp = preferredNamePart.substring(separation);
			int preferredIndex = -1;
			if (!tmp.isEmpty()) {
				preferredIndex = Integer.parseInt(tmp);
			}
			preferredNamePart = preferredNamePart.substring(0, separation);
			for (String usedName : QuiverFrame.getInstance().getNamePool()) {
				for (String namePart : usedName.split(",")) {
					separation = digitSeparation(namePart);
					tmp = namePart.substring(separation);
					int index = -1;
					if (!tmp.isEmpty()) {
						index = Integer.parseInt(tmp);
					}
					namePart = namePart.substring(0, separation);

					if (!namePart.equals(preferredNamePart)) {
						continue;
					}
					used.add(index);
				}
			}
			if (!used.contains(preferredIndex)) {
				if (preferredIndex == -1) {
					name += preferredNamePart + ",";
				} else {
					name += preferredNamePart + preferredIndex + ",";
				}
			} else {
				int i = 1;
				while (true) {
					if (!used.contains(i)) {
						name += preferredNamePart + i + ",";
						used.add(i);
						break;
					}
					i++;
				}
			}
			used.add(preferredIndex);
		}
		if (name.endsWith(",")) {
			name = name.substring(0, name.length() - 1);
		}
		return name;
	}

    @Override
    public void quiverChanged() {

    }
}